package xyz.scootaloo.mono.security.filter

import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
import org.apache.shiro.web.util.WebUtils
import xyz.scootaloo.mono.security.util.KW_HTTP
import xyz.scootaloo.mono.security.util.KW_SHIRO
import xyz.scootaloo.mono.security.util.KW_STATUS
import java.io.IOException
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse

/**
 * 当一条请求访问某路径时, shiro会检查这个请求是否具备访问这个路径所需要的角色
 *
 * 这个类用于做这个逻辑, 当访问某路径指定了多个角色, 访问者包含其中任意一个角色即可访问
 *
 * 计划移除
 *
 * @author flutterdash@qq.com
 * @since 2021/7/26 21:48
 */
class AnyRolesAuthorizationFilter : RolesAuthorizationFilter() {

    override fun postHandle(request: ServletRequest, response: ServletResponse) {
        request.setAttribute(KW_SHIRO.mark, true)
    }

    override fun isAccessAllowed(
        request: ServletRequest, response: ServletResponse, mappedValue: Any?
    ): Boolean {
        if (request.getAttribute(KW_SHIRO.mark) as Boolean || mappedValue == null)
            return true

        val roleList = (mappedValue as Array<*>).map { it.toString() }
        if (roleList.isEmpty())
            return true
        val subject = getSubject(request, response)
        return roleList.stream().anyMatch { role ->
            subject.hasRole(role)
        }
    }

    @Throws(IOException::class)
    override fun onAccessDenied(request: ServletRequest, response: ServletResponse): Boolean {
        return WebUtils.toHttp(response).run {
            characterEncoding = KW_HTTP.CHARSET_ENCODING
            contentType = KW_HTTP.JSON_CONTENT_TYPE
            status = KW_STATUS.UNAUTHORIZED
            false
        }
    }
}
